package com.ubiquando.api.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.gson.stream.JsonReader;
import com.ubiquando.api.server.db.Client;
import com.ubiquando.api.server.db.Dao;
import com.ubiquando.api.server.db.Event;
import com.ubiquando.api.server.db.EventMeeting;
import com.ubiquando.api.server.db.EventPickUp;
import com.ubiquando.api.server.db.PickupClient;

public class API extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2135969261931778580L;

	private static final Logger log = Logger
	.getLogger(Register.class.getName());

	private static final int SET_AUTH_TOKEN = -1;
	private static final int CREATE_MEET_EVENT = 0;
	private static final int CREATE_PCKP_EVENT = 1;
	private static final int CONFIRM_EVENT = 2;
	private static final int UPDATE_LOC = 3;
	private static final int GET_EVENT = 4;
	private static final int START_EVENT = 5;
	private static final int REMOVE_FROM_EVENT = 6;
	private static final int REMOVE_EVENT = 7;
	private static final int FRIEND_REQUEST = 8;
	private static final int ADD_CONTACT = 9;
	private static final int ADD_NEW_PICKUP_TO_MEETING = 10;
	private static final int ADD_PICKUP_TO_MEETING = 11;
	private static final int OFFER_PICKUP = 12;
	private static final int APPROVE_PICKUP = 13;
	private static final int GET_CLIENT = 14;

	private static final String BASE_CLOUD_URL = "https://android.apis.google.com/c2dm/send";
	private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
	private static final String PARAM_REGISTRATION_ID = "registration_id";
	private static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
	private static final String PARAM_COLLAPSE_KEY = "collapse_key";
	private static final String UTF8 = "UTF-8";

	private static final String COLLAPSE_KEY = "message:";
	private static int msgCount = 0;

	private static final String GOOGLE_LOGIN_URL = "https://www.google.com/accounts/ClientLogin";

	private static final int MAX_COUNT = 1023;

	private static final int PICKUP_INVITY_ID = 0;
	private static final int PICKUP_INVITY_LOC = 1;
	private static final int PICKUP_INVITY_LOC_NAME = 2;
	private static final int PICKUP_INVITY_TIME = 3;


	//	private static final String UBI_AUTH_TOKEN = "DQAAALsAAAC74w-5OfsQsOS5ZOz_xtSt60vV8Q9_TaWsxM_"+
	//								"9yyUcM1qh1X68HyUWHFjhl3WH2N_S0LPMVXXLCepwGkY0teUyvZvcOpHMfrVrzQkW"+
	//								"fRFOD-8K0TgaHzkWe5TyC5Y1MqhA8icDId_PI01tomX82XXdIU1CpWyuVXHnGZq5gK"+
	//								"qKr15OE-5SaJurAOZ7lk91ibgkWrmrzArF2nlXvAYAm-HNE4joQ-Dd6u4eBOMpN61vTZ"+
	//										"7yrZFsydQclqlgcBdAH38";


	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {
		resp.setContentType("application/json");
		int method = Integer.parseInt(req.getParameter("method"));
		log.info("In API with POST method " + method);
		switch (method) {
		case SET_AUTH_TOKEN:
			setAuthToken(req, resp);
			break;
		case CREATE_MEET_EVENT:
			createMeetingEvent(req, resp);
			break;
		case CREATE_PCKP_EVENT:
			createPickupEvent(req, resp);
			break;
		case CONFIRM_EVENT:
			confirmEvent(req, resp);
			break;
		case UPDATE_LOC:
			updateClientLocation(req, resp);
			break;
		case GET_EVENT:
			getEvent(req, resp);
			break;
		case START_EVENT:
			startEvent(req, resp);
			break;
		case REMOVE_FROM_EVENT:
			removeFromEvent(req, resp);
			break;
		case REMOVE_EVENT:
			removeEvent(req, resp);
			break;
		case FRIEND_REQUEST:
			friendRequest(req, resp);
			break;
		case ADD_CONTACT:
			addContact(req, resp);
			break;
		case ADD_NEW_PICKUP_TO_MEETING:
			addNewPickup(req, resp);
			break;
		case ADD_PICKUP_TO_MEETING:
			addPickUp(req, resp);
			break;
		case OFFER_PICKUP:
			offerPickup(req, resp);
			break;
		case APPROVE_PICKUP:
			approvePickup(req, resp);
			break;
		case GET_CLIENT:
			getClient(req, resp);
			break;
		}
	}


	private void advanceMessageCount() {
		if(msgCount == MAX_COUNT)
			msgCount = 0;
		else
			msgCount++;
		log.info("advanced msgCount to: "+msgCount);
	}

	private void getClient(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		String clientId = req.getParameter("clientId");

		Client client = Dao.INSTANCE.getClient(clientId);

		if(client == null){
			MyJsonWriter.returnError(resp.getWriter(), "Client not found");
			log.info("return error");
		}else{
			MyJsonWriter.returnClient(resp.getWriter(), client);
			log.info("returned client details");
		}
	}

	private void setAuthToken(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {
		String token = req.getParameter("token");

		log.info("setting auth token : "+token);

		if(Dao.INSTANCE.setClientLogin(token)){
			MyJsonWriter.returnOK(resp.getWriter());
			log.info("token set succefuly");
		}else{
			MyJsonWriter.returnError(resp.getWriter(), "token not set properly");
			log.info("token not set succefuly");
		}
	}

	private void createMeetingEvent(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		String name = req.getParameter("name");
		String creatorId = req.getParameter("creator");
		long time = Long.parseLong(req.getParameter("time"));
		String dest = req.getParameter("dest");
		// String destName = req.getParameter("destName");
		// Client creator = Dao.INSTANCE.getClient(creatorId);

		log.info("Creating meeting: name=" + name + " creatorId=" + creatorId
				+ " time=" + time + " destination=" + dest);

		Event newEvent = Dao.INSTANCE.addMeetingEvent(Event.MEETING_EVENT,
				name, creatorId, time, dest/* , destName */);
		String invites = req.getParameter("invites");
		boolean success = sendInvitations(invites,
				KeyFactory.keyToString(newEvent.getId()), Event.MEETING_EVENT);
		if (success) {
			MyJsonWriter.returnEventId(resp.getWriter(),
					KeyFactory.keyToString(newEvent.getId()));
			log.info("returned ok");
		} else {
			MyJsonWriter.returnError(resp.getWriter(),
			"invitations where not sent correctly");
			log.severe("returned error");
		}
	}

	private boolean sendInvitations(String invites, String eventId , int eventType)
	throws IOException {
		//		System.out.println("did I get here?");
		ArrayList<String> invitationList = parseInvites(invites);
		for (String clientId : invitationList) {
			Client client = Dao.INSTANCE.getClient(clientId);
			messageCloud2Client(client, "eventInvite:" + eventId+"#type:"+eventType);

			log.info("Sent event invitation to client "
					+ KeyFactory.keyToString(client.getId()));
		}
		advanceMessageCount();
		return true;
	}

	private boolean messageCloud2Client(Client client, String msg/*, String collapseKey*/)
	throws IOException {
		log.info("In c2dm notification");

		StringBuilder postDataBuilder = new StringBuilder();
		postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
		.append(client.getRegistrationID());
		postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE).append("=1");
		postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
		.append(COLLAPSE_KEY+msgCount);
		postDataBuilder.append("&").append("data.payload").append("=")
		.append(URLEncoder.encode(msg, UTF8));
		byte[] postData = postDataBuilder.toString().getBytes(UTF8);

		String auth = Dao.INSTANCE.getClientLogin();
		if(auth.isEmpty())
			return false;

		URL url = new URL(BASE_CLOUD_URL);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setDoOutput(true);
		conn.setUseCaches(false);
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-Type",
		"application/x-www-form-urlencoded;charset=UTF-8");
		conn.setRequestProperty("Content-Length",
				Integer.toString(postData.length));
		conn.setRequestProperty("Authorization",
				"GoogleLogin auth=" + auth/*client.getClientLoginToken()*/);

		OutputStream out = conn.getOutputStream();
		out.write(postData);
		out.close();

		log.info("Sent message to cloud. ClientId:"
				+ KeyFactory.keyToString(client.getId()));

		int responseCode = conn.getResponseCode();

		log.info("Received response code " + responseCode + " from cloud");

		if (responseCode == 401 || responseCode == 403) {
			// The token is too old - return false to retry later, will
			// fetch the token
			// from DB. This happens if the password is changed or token
			// expires. Either admin
			// is updating the token, or Update-Client-Auth was received by
			// another server,
			// and next retry will get the good one from database.
			log.warning("got " + responseCode + " from cloud");

			// List<NameValuePair> newPostDataBuilder = new
			// ArrayList<NameValuePair>();

			// HttpClient httpClient = new DefaultHttpClient();
			// HttpPost post = new HttpPost(GOOGLE_LOGIN_URL);

			// newPostDataBuilder.add(new BasicNameValuePair("accountType",
			// "GOOGLE"));
			// newPostDataBuilder.add(new BasicNameValuePair("Email",
			// client.getEmail()));
			// newPostDataBuilder.add(new BasicNameValuePair("Passwd",
			// client.getPwd()));
			// newPostDataBuilder.add(new BasicNameValuePair("service",
			// "ac2dm"));
			// newPostDataBuilder.add(new BasicNameValuePair("source",
			// "huji-ubiquando-1.0"));

			//			StringBuilder data = new StringBuilder();
			//			data.append("accountType").append("=").append("GOOGLE").append("&");
			//			data.append("Email").append("=").append(client.getEmail())
			//					.append("&");
			//			data.append("Passwd").append("=").append(client.getPwd())
			//					.append("&");
			//			data.append("service").append("=").append("ac2dm").append("&");
			//			data.append("source").append("=").append("huji-ubiquando-1.0");
			//
			//			// byte[] newPostData = postDataBuilder.toString().getBytes(UTF8);
			//
			//			URL googleLoginUrl = new URL(GOOGLE_LOGIN_URL);
			//			HttpURLConnection connctn = (HttpURLConnection) googleLoginUrl
			//					.openConnection();
			//			connctn.setDoOutput(true);
			//			connctn.setUseCaches(false);
			//			connctn.setRequestMethod("POST");
			//			// connctn.setRequestProperty("Content-Type",
			//			// "application/x-www-form-urlencoded;charset=UTF-8");
			//
			//			// connctn.setRequestProperty("accountType", "GOOGLE");
			//			// connctn.setRequestProperty("Email", client.getEmail());
			//			// connctn.setRequestProperty("Passwd", client.getPwd());
			//			// connctn.setRequestProperty("service", "ac2dm");
			//			// connctn.setRequestProperty("source", "huji-ubiquando-1.0");
			//
			//			try {
			//				OutputStreamWriter writer = new OutputStreamWriter(
			//						connctn.getOutputStream());
			//				writer.write(data.toString());
			//				writer.close();
			//				// post.setEntity(new UrlEncodedFormEntity(newPostDataBuilder));
			//				// HttpResponse response = httpClient.execute(post);
			//				BufferedReader rd = new BufferedReader(new InputStreamReader(
			//						connctn.getInputStream()));/*
			//													 * new BufferedReader(new
			//													 * InputStreamReader(
			//													 * response
			//													 * .getEntity().getContent
			//													 * ()));
			//													 */
			//
			//				String line = "";
			//				while ((line = rd.readLine()) != null) {
			//					if (line.startsWith("Auth=")) {
			//						client = Dao.INSTANCE.setClientLogin(line.substring(5),
			//								client.getId());
			//						log.warning("got new clientLogin from cloud");
			//						return messageCloud2Client(client, msg);
			//					}
			//				}
			//			} catch (IOException e) {
			//				log.warning("couldn't get new clientlogin from cloud");
			//				return false;
			//			}
			return false;
		}

		// Check for updated token header
		String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
		if (updatedAuthToken != null
				&& !auth.equals(updatedAuthToken)) {
			Dao.INSTANCE.setClientLogin(updatedAuthToken);
		}

		String responseLine = new BufferedReader(new InputStreamReader(
				conn.getInputStream())).readLine();

		// NOTE: You *MUST* use exponential backoff if you receive a 503
		// response code.
		// Since App Engine's task queue mechanism automatically does this
		// for tasks that
		// return non-success error codes, this is not explicitly
		// implemented here.
		// If we weren't using App Engine, we'd need to manually implement
		// this.
		if (responseLine == null || responseLine.equals("")) {
			return false;
		}

		String[] responseParts = responseLine.split("=", 2);
		if (responseParts.length != 2) {
			log.severe("Received ilegal response from cloud");
			return false;
		}

		if (responseParts[0].equals("id")) {
			return true;
		}

		if (responseParts[0].equals("Error")) {
			String err = responseParts[1];
			log.severe("Error occured while communication with cloud");
			// No retry.
			throw new IOException(err);
		}

		return true;
	}

	private ArrayList<String> parseInvites(String invites) throws IOException {
		log.info("parsing invitation json");
		ArrayList<String> invitationList = new ArrayList<String>();
		JsonReader read = new JsonReader(new StringReader(invites));
		read.beginArray();
		while (read.hasNext()) {
			read.beginObject();
			if (read.nextName().equals("participantId")) {
				String id = read.nextString();
				//				String idStr = "";
				//				idStr = idStr + id;
				invitationList.add(id);
				log.info("parsed invite " + id);
			}
			read.endObject();
		}
		read.endArray();
		return invitationList;
	}

	private void createPickupEvent(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		String name = req.getParameter("name");
		String creatorId = req.getParameter("creator");
		long time = Long.parseLong(req.getParameter("time"));
		String dest = req.getParameter("dest");
		// String destName = req.getParameter("destName");
		String location = req.getParameter("location");
		String pickerId = req.getParameter("picker");
		String invites = req.getParameter("invites");

		log.info("Creating pickup event: name=" + name + " creatorId="
				+ creatorId + " time=" + time + " destination=" + dest
				+ " location=" + location + " pickerId=" + pickerId);

		// Client creator = Dao.INSTANCE.getClient(creatorId);
		// Client picker =
		// (creatorId.equals(pickerId))?creator:Dao.INSTANCE.getClient(pickerId);
		Event newEvent = Dao.INSTANCE.addPickupEvent(Event.PICKUP_EVENT, name,
				creatorId, time, dest, /* destName, */location, pickerId);
		boolean success = /* true; */sendPickupInvitations(invites,
				newEvent);
		if (success) {
			MyJsonWriter.returnEventId(resp.getWriter(),
					KeyFactory.keyToString(newEvent.getId()));
			log.info("returned ok");
		} else {
			MyJsonWriter.returnError(resp.getWriter(),
			"invitations where not sent correctly");
			log.severe("returned error");
		}
	}

	private boolean sendPickupInvitations(String invites, Event newEvent) throws IOException {
		ArrayList<String[]> invitationList = parsePickupInvites(invites);
		String eventId = KeyFactory.keyToString(newEvent.getId());

		for (String[] pickupInvity : invitationList) {
			Client client = Dao.INSTANCE.getClient(pickupInvity[PICKUP_INVITY_ID]);
			messageCloud2Client(client, "eventInvite:" + eventId+"#type:"+Event.PICKUP_EVENT+
					"#location:"+pickupInvity[PICKUP_INVITY_LOC]+
					"#locName:"+pickupInvity[PICKUP_INVITY_LOC_NAME]+
					"#time:"+pickupInvity[PICKUP_INVITY_TIME]);

			log.info("Sent event invitation to client "
					+ KeyFactory.keyToString(client.getId()));
		}
		advanceMessageCount();
		return true;
	}


	private ArrayList<String[]> parsePickupInvites(String invites) throws IOException {
		log.info("parsing pickup invitation json");
		ArrayList<String[]> invitationList = new ArrayList<String[]>();
		JsonReader read = new JsonReader(new StringReader(invites));
		read.beginArray();
		while (read.hasNext()) {
			String[] invityProp = new String[4];
			read.beginObject();
			while(read.hasNext()){
				String arg = read.nextName();
				if (arg.equals("participantId")) {
					invityProp[PICKUP_INVITY_ID] = read.nextString();
				}else if(arg.equals("location")){
					invityProp[PICKUP_INVITY_LOC] = read.nextString();
				}else if(arg.equals("locName")){
					invityProp[PICKUP_INVITY_LOC_NAME] = read.nextString();
				}else if(arg.equals("time")){
					invityProp[PICKUP_INVITY_TIME] = ""+ read.nextLong();
				}
			}
			read.endObject();
			invitationList.add(invityProp);
		}
		read.endArray();
		return invitationList;
	}


	private void confirmEvent(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		int eventType = Integer.parseInt(req.getParameter("type"));
		String clientId = req.getParameter("clientId");
		String eventId = req.getParameter("eventId");
		if (eventType == Event.PICKUP_EVENT) {
			confirmPickUpEvent(clientId, eventId, eventType, req, resp);
		} else if (eventType == Event.MEETING_EVENT) {
			confirmMeetingEvent(clientId, eventId, eventType, req, resp);
		}
	}

	private void confirmMeetingEvent(String clientId, String eventId,
			int eventType, HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		log.info("Confirming meeting event: clientId " + clientId
				+ " confirmed eventId " + eventId);

		Event event = Dao.INSTANCE.meetingParticipation(clientId, eventId,
				eventType);
		if (event == null) {
			MyJsonWriter.returnError(resp.getWriter(),
			"problem adding participant to meeting event");
			log.info("returned error");
			return;
		}
		Set<String> unInvites = new HashSet<String>();
		unInvites.add(clientId);
		notifyEventUpdate(event, unInvites);
		MyJsonWriter.returnOK(resp.getWriter());
		log.info("returned ok");
	}

	private void confirmPickUpEvent(String clientId, String eventId,
			int eventType, HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		log.info("Confirming event: clientId " + clientId
				+ " confirmed eventId " + eventId);

		String location = req.getParameter("location");
		String locName = req.getParameter("locName");
		long time = Long.parseLong(req.getParameter("time"));

		Event event = Dao.INSTANCE.pickupParticipation(clientId, eventId,
				eventType, location, locName, time);
		if (event == null) {
			MyJsonWriter.returnError(resp.getWriter(),
			"problem adding participant to meeting event");
			log.info("returned error");
			return;
		}
		Set<String> unInvites = new HashSet<String>();
		unInvites.add(clientId);
		notifyEventUpdate(event, unInvites);
		MyJsonWriter.returnOK(resp.getWriter());
		log.info("returned ok");
	}

	private void notifyEventUpdate(Event event, Set<String> unInvites) throws IOException {
		for (String participantId : event.getParticipants()) {
			if(!unInvites.contains(participantId)){
				Client participant = Dao.INSTANCE.getClient(participantId);
				if (messageCloud2Client(participant,
						"eventUpdate:" + KeyFactory.keyToString(event.getId())+"#type"+event.getType())){
					log.info("notified event"
							+ KeyFactory.keyToString(event.getId()) + " to client "
							+ KeyFactory.keyToString(participant.getId()));
				}
				else
					log.severe("notification of event "
							+ KeyFactory.keyToString(event.getId()) + " to client "
							+ KeyFactory.keyToString(participant.getId())
							+ " failed");
			}
		}
		advanceMessageCount();
	}

	private void updateClientLocation(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		String clientId = req.getParameter("clientId");
		String newLocation = req.getParameter("location");

		log.info("In update location: clientId=" + clientId + " newLocation="
				+ newLocation);

		Client client = Dao.INSTANCE
		.updateClientLocation(clientId, newLocation);

		if (client != null) {
			log.info("client " + clientId + " updated location to "
					+ newLocation);
			notifyLocation(client);

			MyJsonWriter.returnOK(resp.getWriter());
			log.info("returned ok");
		} else {
			log.severe("client " + clientId + " was not found");
			MyJsonWriter.returnError(resp.getWriter(), "client " + clientId
					+ " not found");
			log.severe("returned error");
		}
	}

	private void notifyLocation(Client client) throws IOException {
		log.info("In notifyLocation");
		String clientId = KeyFactory.keyToString(client.getId());
		Set<String> allParticipants = new HashSet<String>();
		Set<String> events = client.getMeetingEvents();
		for(String eventId: events){
			Event event = Dao.INSTANCE.getEvent(eventId, Event.MEETING_EVENT);
			allParticipants.addAll(event.getParticipants());
		}
		events.clear();
		events = client.getPickupEvents();
		for(String eventId: events){
			Event event = Dao.INSTANCE.getEvent(eventId, Event.PICKUP_EVENT);
			Set<String> pickupParticipantIds = event.getParticipants();
			for(String pParticipant: pickupParticipantIds){
				PickupClient pClient = Dao.INSTANCE.getPickupClient(pParticipant);
				allParticipants.add(pClient.getClientId());
			}
		}
		log.info("all participants were added to set");
		if(allParticipants.contains(clientId))
			allParticipants.remove(clientId);
		for(String participantId: allParticipants){
			Client participant = Dao.INSTANCE.getClient(participantId);
			if(participant != null){
				boolean success = messageCloud2Client(
						participant,
						"clientLoc:"
						+ KeyFactory.keyToString(client.getId())
						+ "#location:" + client.getLocation());
				if(success)
					log.info("sent location update to clientId: "+ participantId);
			}
		}
		advanceMessageCount();


		//		Set<String> meetingEvents = client.getMeetingEvents();
		//		for (String mEventId : meetingEvents) {
		//			Event mEvent = Dao.INSTANCE.getEvent(mEventId, Event.MEETING_EVENT);
		//			if (mEvent != null) {
		//				Set<String> participants = mEvent.getParticipants();
		//				for (String participantId : participants) {
		//					Client participant = Dao.INSTANCE.getClient(participantId);
		//					if (participant != null)
		//						messageCloud2Client(
		//								participant,
		//								"clientLoc:"
		//								+ KeyFactory.keyToString(client.getId())
		//								+ "#location:" + client.getLocation());
		//				}
		//				advanceMessageCount();
		//			}
		//		}
		//
		//		Set<String> pickupEvents = client.getPickupEvents();
		//		for (String pEventId : pickupEvents) {
		//			Event pEvent = Dao.INSTANCE.getEvent(pEventId, Event.PICKUP_EVENT);
		//			if (pEvent != null) {
		//				Set<String> participants = pEvent.getParticipants();
		//				for (String pClientId : participants) {
		//					PickupClient pClient = Dao.INSTANCE
		//					.getPickupClient(pClientId);
		//					if (pClient != null) {
		//						Client participant = Dao.INSTANCE.getClient(pClient
		//								.getClientId());
		//						if (participant != null) {
		//							messageCloud2Client(participant, "clientLoc:"
		//									+ KeyFactory.keyToString(client.getId())
		//									+ "#location:" + client.getLocation());
		//						}
		//					}
		//				}
		//				advanceMessageCount();
		//			}
		//		}
	}

	private void startEvent(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String eventId = req.getParameter("eventId");
		int eventType = Integer.parseInt(req.getParameter("type"));

		log.info("In start event: eventId=" + eventId);

		Event event = null;
		if (eventType == Event.MEETING_EVENT)
			event = Dao.INSTANCE.startEvent(eventId, eventType);
		else if (eventType == Event.PICKUP_EVENT)
			event = Dao.INSTANCE.startEvent(eventId, eventType);
		// /////////////////////////////////////////////////////////////////
		// if(event != null){
		// MyJsonWriter.returnOK(resp.getWriter());
		// log.info("returned ok");
		// }else{
		// MyJsonWriter.returnOK(resp.getWriter());
		// log.severe("returned error");
		// }
		// Event event = Dao.INSTANCE.startEvent(eventId);
		if (event != null) {
			if (!notifyEventStart(event)) {
				MyJsonWriter.returnError(resp.getWriter(),
				"error sending update on start event");
				log.severe("returned error");
			} else {
				MyJsonWriter.returnOK(resp.getWriter());
				log.info("returned ok");
			}
		} else {
			MyJsonWriter.returnOK(resp.getWriter());
			log.info("returned ok");
		}
	}

	private boolean notifyEventStart(Event event) throws IOException {
		Set<String> participants = event.getParticipants();
		String key = KeyFactory.keyToString(event.getId());
		boolean success = true, temp = false;
		String creatorId = event.getCreatorId();
		for (String participantId : participants) {
			if(!participantId.equals(creatorId)){
				Client participant = Dao.INSTANCE.getClient(participantId);
				temp = messageCloud2Client(participant, "eventStart:" + key);
				success &= temp;

				if (temp)
					log.info("sent event " + key + " start to client "
							+ KeyFactory.keyToString(participant.getId()));
				else
					log.severe("event " + key + " start was not sent to client "
							+ KeyFactory.keyToString(participant.getId()));
			}
		}
		advanceMessageCount();
		return success;
	}

	private void removeFromEvent(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		String clientId = req.getParameter("clientId");
		String eventId = req.getParameter("eventId");
		int eventType = Integer.parseInt(req.getParameter("type"));

		log.info("In remove from event: clientId=" + clientId + " eventId="
				+ eventId);

		Event event = Dao.INSTANCE.removeParticipation(clientId, eventId,
				eventType);
		Set<String> unInvites = new HashSet<String>();
		unInvites.add(clientId);
		notifyEventUpdate(event, unInvites);
		if (event != null) {
			MyJsonWriter.returnOK(resp.getWriter());
			log.info("returned ok");
		} else {
			MyJsonWriter.returnError(resp.getWriter(),
			"couldn't find event or client");
			log.info("returned error");
		}
	}

	private void getEvent(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String eventId = req.getParameter("eventId");

		log.info("in get event: eventId=" + eventId);

		int eventType = Integer.parseInt(req.getParameter("type"));
		if (eventType == Event.MEETING_EVENT) {
			getMeetingEvent(eventId, req, resp);
		} else if (eventType == Event.PICKUP_EVENT) {
			getPickupEvent(eventId, req, resp);
		}

		// Event event = Dao.INSTANCE.getEvent(eventId, eventType);
		// if(event != null){
		// if(event.getType() == Event.MEETING_EVENT)
		// MyJsonWriter.returnMeetingEvent(resp.getWriter(), (EventMeeting)
		// event);
		// else if(event.getType() == Event.PICKUP_EVENT){
		// MyJsonWriter.returnPickupEvent(resp.getWriter(), (EventPickUp)
		// event);
		// }
		// }else{
		// MyJsonWriter.returnError(resp.getWriter(), "event not found");
		// log.info("returned error");
		// }
	}

	private void getPickupEvent(String eventId, HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		Event event = Dao.INSTANCE.getEvent(eventId, Event.PICKUP_EVENT);
		if (event != null) {
			MyJsonWriter.returnPickupEvent(resp.getWriter(),
					(EventPickUp) event);
			log.info("returned event: " + eventId);
		} else {
			MyJsonWriter.returnError(resp.getWriter(), "event not found");
			log.info("returned error");
		}
	}

	private void getMeetingEvent(String eventId, HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		Event event = Dao.INSTANCE.getEvent(eventId, Event.MEETING_EVENT);
		if (event != null) {
			MyJsonWriter.returnMeetingEvent(resp.getWriter(),
					(EventMeeting) event);
			log.info("returned event: " + eventId);
		} else {
			MyJsonWriter.returnError(resp.getWriter(), "event not found");
			log.info("returned error");
		}
	}

	private void removeEvent(HttpServletRequest req, HttpServletResponse resp) {
		String eventId = req.getParameter("eventId");

		log.info("in remove event: eventId=" + eventId);

		// TODO what should we do?
	}

	private void friendRequest(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String clientId = req.getParameter("clientId");
		String friendEmail = req.getParameter("friend");

		log.info("in friend request: client: " + clientId
				+ " requsting friendship from: " + friendEmail);

		Client client = Dao.INSTANCE.getClient(clientId);

		if (client == null) {
			MyJsonWriter.returnError(resp.getWriter(), "client not found");
			log.severe("returned error");
		} else {
			Client friend = Dao.INSTANCE.findFriend(friendEmail);
			if (friend == null) {
				MyJsonWriter.returnError(resp.getWriter(), "friend not found");
				log.severe("returned error");
			} else {
				if (messageCloud2Client(friend,
						"friendRequest:" + client.getName()+"#clientId:"+KeyFactory.keyToString(client.getId()))) {
					MyJsonWriter.returnOK(resp.getWriter());
					log.info("friend request sent successfuly");
					advanceMessageCount();
				} else {
					MyJsonWriter.returnError(resp.getWriter(),
					"message 2 cloud not sent");
					log.severe("returned error");
				}
			}
		}
	}

	private void addContact(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String client1Id = req.getParameter("clientId1");
		String client2Id = req.getParameter("clientId2");

		log.info("in add contact: client1=" + client1Id + " client2: "
				+ client2Id);

		Client client2 = Dao.INSTANCE.addContact(client1Id, client2Id);

		if (client2 != null) {
			if (messageCloud2Client(client2, "contactAdded:" + client1Id)){
				MyJsonWriter.returnOK(resp.getWriter());
				log.info("returned ok");
				advanceMessageCount();
			}
		} else {
			MyJsonWriter.returnError(resp.getWriter(), "could not add contact");
			log.info("error");
		}

	}

	private void addPickUp(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String meetingId = req.getParameter("meetingId");
		String pickupId = req.getParameter("pickupId");
		String clientId = req.getParameter("clientId");

		Event meetingEvent = Dao.INSTANCE.addPick2Meet(meetingId, pickupId);
		// TODO add notifications
		if (meetingEvent != null) {
			Set<String> unInvites = new HashSet<String>();
			unInvites.add(clientId);
			notifyEventUpdate(meetingEvent, unInvites);
			MyJsonWriter.returnOK(resp.getWriter());
			log.info("returned ok");
		} else {
			MyJsonWriter.returnError(resp.getWriter(), "could not add contact");
			log.info("returned error");
		}
	}

	private void addNewPickup(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String name = req.getParameter("name");
		String creatorId = req.getParameter("creator");
		long time = Long.parseLong(req.getParameter("time"));
		String dest = req.getParameter("dest");
		// String destName = req.getParameter("destName");
		String location = req.getParameter("location");
		String pickerId = req.getParameter("picker");
		String invites = req.getParameter("invites");
		String meetingId = req.getParameter("meetingId");

		log.info("Creating pickup event: name=" + name + " creatorId="
				+ creatorId + " time=" + time + " destination=" + dest
				+ " location=" + location + " pickerId=" + pickerId);
		Event newEvent = Dao.INSTANCE.addPickupEvent(Event.PICKUP_EVENT, name,
				creatorId, time, dest, /* destName, */location, pickerId);
		if (newEvent != null) {
			Event meetingEvent = Dao.INSTANCE.addPick2Meet(meetingId,
					KeyFactory.keyToString(newEvent.getId()));
			if (meetingEvent != null) {
				Set<String> unInvites = new HashSet<String>();
				unInvites.add(pickerId);
				notifyEventUpdate(meetingEvent, unInvites);
				MyJsonWriter.returnOK(resp.getWriter());
				log.info("returned ok");
			} else {
				MyJsonWriter.returnError(resp.getWriter(),
				"could not add contact");
				log.info("returned error");
				return;
			}

			boolean success = /* true; */sendInvitations(invites,
					KeyFactory.keyToString(newEvent.getId()), Event.PICKUP_EVENT);
			if (success) {
				MyJsonWriter.returnEventId(resp.getWriter(),
						KeyFactory.keyToString(newEvent.getId()));
				log.info("returned ok");
			} else {
				MyJsonWriter.returnError(resp.getWriter(),
				"invitations where not sent correctly");
				log.severe("returned error");
			}
		} else {
			MyJsonWriter.returnError(resp.getWriter(),
			"invitations where not sent correctly");
			log.severe("returned error");
		}
	}

	private void offerPickup(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String clientId = req.getParameter("clientId");
		String friendId = req.getParameter("friendId");
		String eventId = req.getParameter("eventId");

		log.info("in offer pickup: client: " + clientId
				+ " offering pickup to: " + friendId
				+ "on pickup event: " + eventId);

		Client client = Dao.INSTANCE.getClient(clientId);

		if (client == null) {
			MyJsonWriter.returnError(resp.getWriter(), "client not found");
			log.severe("returned error");
		} else {
			Client friend = Dao.INSTANCE.getClient(friendId);
			if (friend == null) {
				MyJsonWriter.returnError(resp.getWriter(), "friend not found");
				log.severe("returned error");
			} else {
				if (messageCloud2Client(friend,
						"offerPickup:" + client.getName()+"#eventId:"+eventId)) {
					MyJsonWriter.returnOK(resp.getWriter());
					log.info("friend request sent successfuly");
					advanceMessageCount();
				} else {
					MyJsonWriter.returnError(resp.getWriter(),
					"message 2 cloud not sent");
					log.severe("returned error");
				}
			}
		}
	}

	private void approvePickup(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		String pickerId = req.getParameter("pickerId");
		//		String client2Id = req.getParameter("client2Id");
		String eventId = req.getParameter("eventId");

		log.info("in approve pickup: pickerId=" + pickerId + " eventid: "
				+ eventId);

		//TODO addPicker function
		Event event = Dao.INSTANCE.addPicker(pickerId, eventId);

		if (event != null) {

			Client client = Dao.INSTANCE.getClient(pickerId);
			if(client != null){
				if (messageCloud2Client(client, "pickupConfirmed:" + eventId)){
					MyJsonWriter.returnOK(resp.getWriter());
					log.info("returned ok");
					advanceMessageCount();
				}
			}else{
				MyJsonWriter.returnError(resp.getWriter(), "didn't find client");
				log.info("returned error");
			}

			//			if (messageCloud2Client(client2, "pickupConfirmed:" + pickerId)){
			//				MyJsonWriter.returnOK(resp.getWriter());
			//				log.info("returned ok");
			//			}
			Set<String> unInvites = new HashSet<String>();
			unInvites.add(KeyFactory.keyToString(client.getId()));
			unInvites.add(pickerId);
			notifyEventUpdate(event, unInvites);
			MyJsonWriter.returnOK(resp.getWriter());
		} else {
			MyJsonWriter.returnError(resp.getWriter(), "could not add contact");
			log.info("returned ok");
		}

	}
}
